home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / Kibitz / AEchess.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-22  |  51.6 KB  |  1,703 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        aechess.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. **
  10. ** This is the custom AppleEvents code.  The required AppleEvents code is in
  11. ** the file AppleEvents.c, which is Keith Rollin's work. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  20. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  21. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  22.  
  23. #ifndef __AEUTILS__
  24. #include <AEUtils.h>
  25. #endif
  26.  
  27. #ifndef __ERRORS__
  28. #include <Errors.h>
  29. #endif
  30.  
  31. #ifndef __MEMORY__
  32. #include <Memory.h>
  33. #endif
  34.  
  35. #ifndef __NOTIFICATION__
  36. #include <Notification.h>
  37. #endif
  38.  
  39. #ifndef __OSUTILS__
  40. #include <OSUtils.h>
  41. #endif
  42.  
  43. #ifndef __PPC__
  44. #include "PPC.h"
  45. #endif
  46.  
  47. #ifndef __RESOURCES__
  48. #include <Resources.h>
  49. #endif
  50.  
  51. #ifndef __SOUND__
  52. #include <Sound.h>
  53. #endif
  54.  
  55. #ifndef __STRING__
  56. #include <String.h>
  57. #endif
  58.  
  59. #ifndef THINK_C
  60. #ifndef __SYSEQU__
  61. #include <SysEqu.h>
  62. #endif
  63. #endif
  64.  
  65. #ifndef __TOOLUTILS__
  66. #include <ToolUtils.h>
  67. #endif
  68.  
  69. #ifndef __TEXTEDITCONTROL__
  70. #include <TextEditControl.h>
  71. #endif
  72.  
  73. #ifndef __UTILITIES__
  74. #include <Utilities.h>
  75. #endif
  76.  
  77.  
  78.  
  79. /*****************************************************************************/
  80.  
  81.  
  82.  
  83. #define PRIORITY        kAENormalPriority
  84. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  85.  
  86.  
  87.  
  88. /*****************************************************************************/
  89.  
  90.  
  91.  
  92. static pascal void    CancelNotify(NMRecPtr nmReqPtr);
  93. static void            GetFullPathAndAppName(StringPtr path, StringPtr app);
  94.  
  95. static void            GetAppFullPath(StringPtr path);
  96.  
  97.  
  98.  
  99. /*****************************************************************************/
  100.  
  101.  
  102.  
  103. struct triplets{
  104.     AEEventClass    theEventClass;
  105.     AEEventID        theEventID;
  106.     ProcPtr            theHandler;
  107. };
  108. typedef struct triplets triplets;
  109. static triplets keywordsToInstall[] = {
  110.     { kCoreEventClass,        kAEAnswer,                DoAEAnswer },
  111.     { kCustomEventClass,    kibitzAESendGame,        ReceiveGame },
  112.     { kCustomEventClass,    kibitzAESendMssg,        ReceiveMssg }
  113. };        /* These are the custom AppleEvents. */
  114.  
  115.  
  116.  
  117. /*****************************************************************************/
  118.  
  119.  
  120.  
  121. extern Boolean        gHasAppleEvents;
  122. extern Boolean        gHasPPCToolbox;
  123.  
  124. extern RgnHandle    gCurrentCursorRgn;
  125. extern Cursor        *gCurrentCursor;
  126.  
  127.  
  128.  
  129. /*****************************************************************************/
  130. /*****************************************************************************/
  131.  
  132.  
  133.  
  134. /* InitCustomAppleEvents
  135. **
  136. ** Install our custom AppleEvents.  This is done in addition to installing
  137. ** the required AppleEvents.  InitAppleEvents, which installs the required
  138. ** AppleEvents, must be called first, since it sets up some global values. */
  139.  
  140. #pragma segment AppleEvents
  141. void    InitCustomAppleEvents(void)
  142. {
  143.     OSErr    err;
  144.     short    i;
  145.  
  146.     if (gHasAppleEvents) {
  147.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  148.             err = AEInstallEventHandler(
  149.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  150.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  151.                 keywordsToInstall[i].theHandler,    /* The AppleEvent handler. */
  152.                 0L,                                    /* Unused refcon.           */
  153.                 false                                /* Only for our app.       */
  154.             );
  155.  
  156.             if (err) {
  157.                 Alert(rErrorAlert, (ModalFilterProcPtr)AlertFilter);
  158.                 return;
  159.             }
  160.         }
  161.     }
  162. }
  163.  
  164.  
  165.  
  166. /*****************************************************************************/
  167.  
  168.  
  169.  
  170. #pragma segment AppleEvents
  171. pascal OSErr    DoAEAnswer(AppleEvent message, AppleEvent reply, long refcon)
  172. {
  173. #pragma unused (refcon)
  174.  
  175.     OSErr    err;
  176.  
  177.     gCurrentCursor = nil;
  178.         /* Force re-calc of cursor region and cursor to use. */
  179.  
  180.     err = ReceiveGameReply(message, reply);
  181.  
  182.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  183.         &reply,                    /* The AppleEvent.              */
  184.         keyReplyErr,            /* AEKeyword                 */
  185.         typeShortInteger,        /* Desired type.             */
  186.         (Ptr)&err,                /* Pointer to area for data. */ 
  187.         sizeof(short)            /* Size of data area.         */
  188.     );
  189.  
  190.     return(noErr);
  191. }
  192.  
  193.  
  194.  
  195. /*****************************************************************************/
  196.  
  197.  
  198.  
  199. /* SendGame
  200. **
  201. ** This routine acquires an opponent and sends the opponent the current game.
  202. ** Various changes are made to the game record to indicate that this game
  203. ** has an opponent, which color we are, where we are located (so the
  204. ** opponent can send moves back), the ID of our game, etc.  Once this
  205. ** information is in the game record, the game is transmitted to the
  206. ** opponent.  Upon receiving the game, the opponent sends back confirmation,
  207. ** which also includes the ID of the game on the opponent's end.  The return
  208. ** information is sent back as via AEAnswer, so we will extablish a two-player
  209. ** game until we receive this event.  Once we do establish a two-player game,
  210. ** we will store the opponent's game ID in the game record as well.  With our
  211. ** ID and the opponents ID, we will be able to determine which game the data
  212. ** is for at both ends.  This allows two opponents to play multiple games with
  213. ** the same machines. */
  214.  
  215. #pragma segment AppleEvents
  216. OSErr    SendGame(FileRecHndl frHndl, short sendReason, StringPtr nbpType)
  217. {
  218.     AEAddressDesc    locOfOpponent;
  219.     Boolean            twoPlayer;
  220.     OSErr            err;
  221.     AEDescList        sendGameList;
  222.     long            gameID[2], size;
  223.     char            hstate;
  224.     Ptr                ptr1, ptr2;
  225.     GameListHndl    gameMoves;
  226.     AppleEvent        theAevt, reply;
  227.     short            replyType;
  228.     Str255            macText, appText, opponentName, reconnectPath;
  229.     Str32            reconnectApp;
  230.     Handle            userNameHndl;
  231.  
  232.     sendGameList.dataHandle = theAevt.dataHandle = reply.dataHandle = nil;
  233.         /* Make sure disposing of the descriptors is okay in all cases.
  234.         ** This will not be necessary after 7.0b3, since the calls that
  235.         ** attempt to create the descriptors will nil automatically
  236.         ** upon failure. */
  237.  
  238.     err = noErr;
  239.         /* We may not make the first operation that can cause an error,
  240.         ** so we have to initialize err. */
  241.  
  242.     locOfOpponent.dataHandle = nil;
  243.         /* Make it safe to dispose of in all cases. */
  244.  
  245.     if ((*frHndl)->doc.resync < ((*frHndl)->doc.sendReason = sendReason))
  246.         (*frHndl)->doc.resync = sendReason;
  247.             /* Bump up resync, if needed. */
  248.  
  249.     UpdateTime(frHndl, false);
  250.         /* Make sure timers are current before we give them to opponent. */
  251.  
  252.     twoPlayer = (*frHndl)->doc.twoPlayer;
  253.     if (!twoPlayer) {            /* If we don't have a live opponent yet... */
  254.         GetIndString(macText, rPPCText, sTitleText);
  255.         GetIndString(appText, rPPCText, sAppText);
  256.         err = MakeTarget(&locOfOpponent, false, kAEWaitReply,
  257.             macText, appText, (PPCFilterProcPtr)KibitzPortFilter, (char *)nbpType);
  258.                 /* Generate the target for our opponent. */
  259.         (*frHndl)->doc.gameID_0      = gameID[0] = (TickCount() & 0xFFFFFFFE);
  260.         (*frHndl)->doc.gameID_1      = gameID[0];
  261.         (*frHndl)->doc.locOfOpponent = locOfOpponent;
  262.     }
  263.     else locOfOpponent = (*frHndl)->doc.locOfOpponent;
  264.  
  265.     if (!err) {        /* If we have an opponent... */
  266.         err = AECreateList(        /* CREATE THE LIST TO HOLD THE GAME. */
  267.             nil,                /* No factoring.             */
  268.             0,                    /* No factoring.             */
  269.             false,                /* Not an AppleEvent record. */
  270.             &sendGameList        /* List descriptor.             */
  271.         );
  272.     }
  273.  
  274.     if (!err) {        /* If we have an empty list to add to... */
  275.         hstate = LockHandleHigh((Handle)frHndl);
  276.         ptr1   = (Ptr)&((*frHndl)->doc);
  277.         ptr2   = (Ptr)&((*frHndl)->doc.endSendInfo);
  278.         size   = (long)ptr2 - (long)ptr1;
  279.         err = AEPutPtr(        /* ADD BOARD INFO TO THE APPLEEVENT. */
  280.             &sendGameList,    /* List to add to.                     */
  281.             1L,                /* Make this element #1.             */
  282.             typeTheBoard,    /* It is a descriptor for the board. */
  283.             ptr1,            /* Pointer to the board data.         */
  284.             size            /* Size of the board data.             */
  285.         );
  286.         HSetState((Handle)frHndl, hstate);
  287.     }
  288.  
  289.     /* For a new opponent, the field twoPlayer in sendGameList (to be sent
  290.     ** to the opponent) indicates that there is no live opponent.  When the
  291.     ** receiver gets a board with twoPlayer false, this indicates a new game
  292.     ** is being set up.  If twoPlayer is true, then it is an existing game. */
  293.  
  294.     if (!err) {        /* If we could add the board info to the list... */
  295.         gameMoves = (*frHndl)->doc.gameMoves;
  296.         size      = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  297.         hstate    = LockHandleHigh((Handle)gameMoves);
  298.         err = AEPutPtr(            /* ADD GAME MOVES TO THE LIST.             */
  299.             &sendGameList,        /* List to add to.                         */
  300.             2L,                    /* Make this element #2.                 */
  301.             typeGameMoves,        /* Descriptor for the moves of the game. */
  302.             (Ptr)(*gameMoves),    /* Pointer to the move data.             */
  303.             size                /* Size of the move data.                 */
  304.         );
  305.         HSetState((Handle)gameMoves, hstate);
  306.     }
  307.  
  308.     if ((!err) && (!twoPlayer)) {
  309.         hstate = LockHandleHigh((Handle)frHndl);
  310.         ptr1   = (Ptr)&((*frHndl)->fileState.fss);
  311.         err = AEPutPtr(            /* ADD FSSpec TO LIST TO PASS THE GAME NAME. */
  312.             &sendGameList,        /* List to add to.         */
  313.             3L,                    /* Make this element #3. */
  314.             typeFSS,            /* FSSpec descriptor.     */
  315.             ptr1,                /* Pointer to the data.     */
  316.             sizeof(FSSpec)        /* Size of the data.     */
  317.         );
  318.         HSetState((Handle)frHndl, hstate);
  319.         if (!err) {
  320.             opponentName[0] = 0;
  321.             if (userNameHndl = GetResource('STR ', -16096))
  322.                 pcpy(opponentName, (StringPtr)(*userNameHndl));
  323.             err = AEPutPtr(            /* ADD USER NAME TO LIST. */
  324.                 &sendGameList,        /* List to add to.             */
  325.                 4L,                    /* Make this element #4.     */
  326.                 typePascal,            /* Pascal string descriptor. */
  327.                 (Ptr)opponentName,    /* Pointer to the data.         */
  328.                 opponentName[0] + 1    /* Size of the data.         */
  329.             );
  330.             if (!err) {
  331.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  332.                 err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  333.                     &sendGameList,            /* List to add to.             */
  334.                     5L,                        /* Make this element #5.     */
  335.                     typePascal2,            /* Pascal string descriptor. */
  336.                     (Ptr)reconnectPath,        /* Pointer to the data.         */
  337.                     reconnectPath[0] + 1    /* Size of the data.         */
  338.                 );
  339.                 if (!err) {
  340.                     err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  341.                         &sendGameList,            /* List to add to.             */
  342.                         6L,                        /* Make this element #5.     */
  343.                         typePascal3,            /* Pascal string descriptor. */
  344.                         (Ptr)reconnectApp,        /* Pointer to the data.         */
  345.                         reconnectApp[0] + 1        /* Size of the data.         */
  346.                     );
  347.                 }
  348.             }
  349.         }
  350.     }
  351.  
  352.     if (!err) {        /* If we could add the game moves to the list... */
  353.         err = AECreateAppleEvent(            /* CREATE EMPTY APPLEEVENT.     */
  354.             kCustomEventClass,                /* Event class.                 */
  355.             kibitzAESendGame,                /* Event ID.                 */
  356.             &locOfOpponent,                    /* Address of receiving app. */
  357.             kAutoGenerateReturnID,            /* This value causes the     */
  358.                                             /* AppleEvent manager to     */
  359.                                             /* assign a return ID that     */
  360.                                             /* is unique to the session. */
  361.             kAnyTransactionID,                /* Ignore transaction ID.     */
  362.             &theAevt                        /* Location of event.         */
  363.         );
  364.     }
  365.  
  366.     if (!err) {        /* If we have an empty AppleEvent... */
  367.         err = AEPutParamDesc(    /* PUT THE LIST INTO THE APPLEEVENT.  */
  368.             &theAevt,            /* AppleEvent to add list to.          */
  369.             keyDirectObject,    /* This is our direct (only) object.  */
  370.             &sendGameList        /* The list to add to the AppleEvent. */
  371.         );
  372.     }
  373.  
  374.     replyType = (!twoPlayer) ? kAEQueueReply : kAENoReply;
  375.         /* Queue a reply only for a new game. */
  376.  
  377.     if (!err) {        /* If we have an AppleEvent ready to send... */
  378.         err = AESend(        /* SEND APPLEEVENT.                */
  379.             &theAevt,        /* Our Apple Event to send.        */
  380.             &reply,            /* We may have a reply.            */
  381.             replyType,        /* Type of reply.                */
  382.             PRIORITY,        /* App. send priority.            */
  383.             0,                /* We aren't waiting.            */
  384.             nil,            /* We aren't waiting.            */
  385.             nil                /* EventFilterProcPtr.            */
  386.         );
  387.     }
  388.     if (replyType == kAEQueueReply)
  389.         if (locOfOpponent.descriptorType == typeProcessSerialNumber)
  390.             err = ReceiveGameReply(reply, reply);
  391.                 /* If we want a queue reply, and if we are sending to ourselves,
  392.                 ** then we already have the reply.  Since we are sending to
  393.                 ** ourselves, we don't have to wait for an event.  Stuff happens
  394.                 ** right away.  We're (probably) happy. */
  395.  
  396.     AEDisposeDesc(&sendGameList);
  397.     AEDisposeDesc(&theAevt);
  398.     AEDisposeDesc(&reply);
  399.         /* Dispose of the descriptors, created or not.
  400.         ** If not created, no harm done by calling. */
  401.  
  402.     if (err) {
  403.         AEDisposeDesc(&locOfOpponent);
  404.             /* If we didn't connect, get rid of the target descriptor. */
  405.  
  406.         (*frHndl)->doc.gameID_0 = 0;
  407.         (*frHndl)->doc.gameID_1 = 0;
  408.             /* Mark this window so that it will never be found if we somehow
  409.             ** do get an answer from the receiver, even after failure. */
  410.     }
  411.  
  412.     return(err);
  413. }
  414.  
  415.  
  416.  
  417. /*****************************************************************************/
  418.  
  419.  
  420.  
  421. /* This code is executed only after an game is initially sent and we receive
  422. ** an AEAnswer event.  The "answer" is acknowledgment that the opponent
  423. ** received the game and that the opponent is set up for a two-player game.
  424. ** In the reply, we receive the opponent's game ID, which is used to match
  425. ** up which game receives the AppleEvents. */
  426.  
  427. #pragma segment AppleEvents
  428. pascal OSErr    ReceiveGameReply(AppleEvent message, AppleEvent reply)
  429. {
  430. #pragma unused (reply)
  431.  
  432.     OSErr            err, replyErr;
  433.     DescType        actualType;
  434.     long            gameID[2], actualSize, mssgSize;
  435.     char            hstate;
  436.     WindowPtr        window;
  437.     FileRecHndl        frHndl;
  438.     Handle            mssgData;
  439.     Str32            opponentName, zone, machine, application;
  440.     Str255            reconnectPath;
  441.     Str32            reconnectApp;
  442.     AEAddressDesc    locOfOpponent;
  443.  
  444.     err = AEGetParamPtr(        /* CHECK FOR A RECEIVER ERROR... */
  445.         &message,                /* The AppleEvent.              */
  446.         keyReplyErr,            /* AEKeyword                 */
  447.         typeShortInteger,        /* Desired type.             */
  448.         &actualType,            /* Type code.                 */
  449.         (Ptr)&replyErr,            /* Pointer to area for data. */ 
  450.         sizeof(short),            /* Size of data area.         */
  451.         &actualSize                /* Returned size of data.     */
  452.     );
  453.     if (!err) err = replyErr;
  454.  
  455.     if (!err) {
  456.         err = AEGetParamPtr(    /* GET RECEIVER GAME ID. */
  457.             &message,            /* The AppleEvent.              */
  458.             keyGameID,            /* AEKeyword                 */
  459.             typeDoubleLong,        /* Desired type.             */
  460.             &actualType,        /* Type code.                 */
  461.             (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  462.             2 * sizeof(long),    /* Size of data area.         */
  463.             &actualSize            /* Returned size of data.     */
  464.         );
  465.     }
  466.  
  467.     if (!err) {        /* If we got the receiver game ID... */
  468.  
  469.         window = GetGameWindow(gameID[1], gameID[1]);
  470.             /* The ID's are still both ours, since this is where we
  471.             ** get the receiver's ID returned.  gameID[0] holds the
  472.             ** receiver's ID, and gameID[1] holds ours. */
  473.  
  474.         if (window) {
  475.             frHndl = (FileRecHndl)GetWRefCon(window);
  476.             if (!(*frHndl)->doc.twoPlayer) {
  477.                 err = AEGetParamPtr(
  478.                     &message,            /* The AppleEvent.              */
  479.                     keyPascalReply,        /* AEKeyword                 */
  480.                     typePascal,            /* Desired type.             */
  481.                     &actualType,        /* Type code.                 */
  482.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  483.                     sizeof(Str32),        /* Size of data area.         */
  484.                     &actualSize            /* Returned size of data.     */
  485.                 );
  486.  
  487.                 (*frHndl)->doc.opponentName[0] = 0;
  488.                 if (!err) {
  489.                     (*frHndl)->doc.gameID_1 = gameID[0];
  490.                     pcpy(&(*frHndl)->doc.opponentName[0], opponentName);
  491.                     SetOpponentType(frHndl, kTwoPlayer);
  492.                     locOfOpponent = (*frHndl)->doc.locOfOpponent;
  493.                     zone[0] = machine[0] = 0;
  494.                     GetTargetInfo(locOfOpponent, zone, machine, application);
  495.                     pcpy(&(*frHndl)->doc.opponentZone[0], zone);
  496.                     pcpy(&(*frHndl)->doc.opponentMachine[0], machine);
  497.  
  498.                     err = AEGetParamPtr(
  499.                         &message,            /* The AppleEvent.              */
  500.                         keyPascal2Reply,    /* AEKeyword                 */
  501.                         typePascal2,        /* Desired type.             */
  502.                         &actualType,        /* Type code.                 */
  503.                         (Ptr)reconnectPath,    /* Pointer to area for data. */ 
  504.                         sizeof(Str255),        /* Size of data area.         */
  505.                         &actualSize            /* Returned size of data.     */
  506.                     );
  507.                     (*frHndl)->doc.reconnectPath[0] = 0;
  508.                     if (!err) pcpy(&(*frHndl)->doc.reconnectPath[0], reconnectPath);
  509.  
  510.                     err = AEGetParamPtr(
  511.                         &message,            /* The AppleEvent.              */
  512.                         keyPascal3Reply,    /* AEKeyword                 */
  513.                         typePascal3,        /* Desired type.             */
  514.                         &actualType,        /* Type code.                 */
  515.                         (Ptr)reconnectApp,    /* Pointer to area for data. */ 
  516.                         sizeof(Str32),        /* Size of data area.         */
  517.                         &actualSize            /* Returned size of data.     */
  518.                     );
  519.                     (*frHndl)->doc.reconnectApp[0] = 0;
  520.                     if (!err) pcpy(&(*frHndl)->doc.reconnectApp[0], reconnectApp);
  521.  
  522.                     if (!err) {
  523.                         err = AEGetParamPtr(
  524.                             &message,                /* The AppleEvent.              */
  525.                             keyTextMessage,            /* AEKeyword                 */
  526.                             typeMssg,                /* Desired type.             */
  527.                             &actualType,            /* Type code.                 */
  528.                             nil,                    /* Pointer to area for data. */ 
  529.                             0,                        /* Size of data area.         */
  530.                             &mssgSize                /* Returned size of data.     */
  531.                         );
  532.                     }
  533.                     mssgData = nil;
  534.                     if (!err) {        /* Get the data... */
  535.                         mssgData = NewHandle(mssgSize);
  536.                         if (mssgData) {
  537.                             hstate = LockHandleHigh(mssgData);
  538.                             err = AEGetParamPtr(
  539.                                 &message,                /* The AppleEvent.              */
  540.                                 keyTextMessage,            /* AEKeyword                 */
  541.                                 typeMssg,                /* Desired type.             */
  542.                                 &actualType,            /* Type code.                 */
  543.                                 *mssgData,                /* Pointer to area for data. */ 
  544.                                 mssgSize,                /* Size of data area.         */
  545.                                 &actualSize                /* Returned size of data.     */
  546.                             );
  547.                         }
  548.                         else err = memFullErr;
  549.                     }
  550.                     if (!err)
  551.                         mssgData = CTESwapText((*frHndl)->doc.message[kMessageIn], mssgData, true);
  552.                     if (mssgData) DisposHandle(mssgData);
  553.  
  554.                     if (err == errAEDescNotFound) err = noErr;
  555.                 }
  556.                 if (err) (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  557.                 else GetDateTime(&((*frHndl)->doc.timeLastReceive));
  558.             }
  559.         }
  560.     }
  561.  
  562.     return(err);
  563. }
  564.  
  565.  
  566.  
  567. /*****************************************************************************/
  568.  
  569.  
  570.  
  571. /* ReceiveGame
  572. **
  573. ** This routine receives a board from an opponent.  It receives it for various
  574. ** purposes.  These are:
  575. **   1) Establishing a new game.
  576. **   2) Receiving a move.
  577. **   3) Receiving a new board position, due to scrolling.
  578. **
  579. ** Establishing a new game is determined by the fact that the value twoPlayer
  580. ** is false.  If it is a previously established game, then this field is true.
  581. **
  582. ** If it is a previously established game, then whether or not it is a new move
  583. ** is determined by field "sendReason".  If sendReason != kIsMove, then it is some
  584. ** other change, such as scrolling or resyncing by of the sender.
  585. ** These other cases should not cause a win/loss/tie dialog to appear.
  586. **
  587. ** If it is a regular move, (sendReason == kIsMove), then the win/loss/draw dialogs
  588. ** should be displayed, if the game is indeed over after the move. */
  589.  
  590. #pragma segment AppleEvents
  591. pascal OSErr    ReceiveGame(AppleEvent message, AppleEvent reply, long refcon)
  592. {
  593. #pragma unused (refcon)
  594.  
  595.     OSErr            err;
  596.     FileRecHndl        frHndl, newFrHndl, oldFrHndl, mssgFrHndl;
  597.     FileRecPtr        frPtr;
  598.     AEDescList        receiveGameList;
  599.     char            hstate;
  600.     Ptr                ptr1, ptr2;
  601.     long            size, gameID[2];
  602.     Boolean            twoPlayer;
  603.     AEAddressDesc    senderTarget;
  604.     AEKeyword        ignoredKeyWord;
  605.     DescType        ignoredType;
  606.     Size            ignoredSize;
  607.     GameListHndl    gameMoves;
  608.     WindowPtr        oldPort, window, fwindow, behindWindow;
  609.     WindowPeek        wpeek;
  610.     FSSpec            myFSS;
  611.     Str32            opponentName, zone, machine, application;
  612.     Str255            reconnectPath;
  613.     Str32            reconnectApp;
  614.     Handle            userNameHndl, hText;
  615.     short            i, drawBtnState, sendReason, myColor, invertBoard, fromSq, toSq;
  616.     GameListHndl    oldGame, newGame;
  617.     GameElement        *optr, *nptr;
  618.     short            oldGameIndex, newGameIndex, oldNumMoves, newNumMoves, identical;
  619.     TEHandle        te;
  620.  
  621.     err = noErr;
  622.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  623.         &reply,                    /* The AppleEvent.              */
  624.         keyReplyErr,            /* AEKeyword                 */
  625.         typeShortInteger,        /* Desired type.             */
  626.         (Ptr)&err,                /* Pointer to area for data. */ 
  627.         sizeof(short)            /* Size of data area.         */
  628.     );
  629.  
  630.     receiveGameList.dataHandle = nil;
  631.         /* Make sure disposing of the descriptors is okay in all cases.
  632.         ** This will not be necessary after 7.0b3, since the calls that
  633.         ** attempt to create the descriptors will nil automatically
  634.         ** upon failure. */
  635.  
  636.     IncNewFileNum(false);
  637.     err = AppNewDocument(&newFrHndl, ksOrigName);
  638.     IncNewFileNum(true);
  639.  
  640.     if (err) return(err);
  641.  
  642.     /* We have a new document... */
  643.     err = AEGetParamDesc(    /* GET THE APPLEEVENT LIST.  */
  644.         &message,            /* AppleEvent to holding list.          */
  645.         keyDirectObject,    /* This is our direct (only) object.  */
  646.         typeWildCard,        /* Desired type is game list.          */
  647.         &receiveGameList    /* The list to add to the AppleEvent. */
  648.     );
  649.  
  650.     if (!err) {        /* If we got the list descriptor... */
  651.         hstate = LockHandleHigh((Handle)newFrHndl);
  652.         ptr1   = (Ptr)&((*newFrHndl)->doc);
  653.         ptr2   = (Ptr)&((*newFrHndl)->doc.endSendInfo);
  654.         size   = (long)ptr2 - (long)ptr1;
  655.         err = AEGetNthPtr(        /* GET BOARD INFO FROM THE LIST.     */
  656.             &receiveGameList,    /* List to get from.                 */
  657.             1L,                    /* Get first item in list.             */
  658.             typeTheBoard,        /* First item is the board.             */
  659.             &ignoredKeyWord,    /* Returned keyword -- we know.         */
  660.             &ignoredType,        /* Returned type -- we know.         */
  661.             ptr1,                /* Where to put the board info.         */
  662.             size,                /* Size of the board.                 */
  663.             &ignoredSize        /* Actual size -- we know.             */
  664.         );
  665.         HSetState((Handle)newFrHndl, hstate);
  666.     }
  667.  
  668.     if (!err) {        /* If we got the board... */
  669.         gameMoves = (*newFrHndl)->doc.gameMoves;
  670.         size      = (*newFrHndl)->doc.numGameMoves * sizeof(GameElement);
  671.         SetHandleSize((Handle)gameMoves, size);
  672.         err = MemError();
  673.         if (!err) {
  674.             hstate = LockHandleHigh((Handle)gameMoves);
  675.             err = AEGetNthPtr(        /* GET GAME MOVES FROM THE LIST.     */
  676.                 &receiveGameList,    /* List to get from.                 */
  677.                 2L,                    /* Get second item in list.             */
  678.                 typeGameMoves,        /* Second item is the game moves.     */
  679.                 &ignoredKeyWord,    /* Returned keyword -- we know.         */
  680.                 &ignoredType,        /* Returned type -- we know.         */
  681.                 (Ptr)(*gameMoves),    /* Where to put the moves.             */
  682.                 size,                /* Size of the board.                 */
  683.                 &ignoredSize        /* Actual size -- we know.             */
  684.             );
  685.             HSetState((Handle)gameMoves, hstate);
  686.         }
  687.     }
  688.  
  689.  
  690.  
  691.     if (!err) {
  692.  
  693.         /* We now have the board and game moves, in newFrHndl.  This is either a
  694.         ** new opponent, or an update from an old opponent.  Let's see... */
  695.  
  696.         twoPlayer = (*newFrHndl)->doc.twoPlayer;
  697.         (*newFrHndl)->doc.twoPlayer = false;
  698.             /* See if this is an already existing opponent, or a new one. */
  699.     
  700.         if (!twoPlayer) {        /* If new game... */
  701.             err = AEGetAttributeDesc(    /* GET ADDRESS OF NEW OPPONENT.     */
  702.                 &message,                /* Get address of sender from message.         */
  703.                 keyAddressAttr,            /* We want an address.                         */
  704.                 typeWildCard,            /* We want the address of the sender.         */
  705.                 &senderTarget            /* Address of sender.                         */
  706.             );
  707.             if (!err) {
  708.                 (*newFrHndl)->doc.twoPlayer     = true;
  709.                 (*newFrHndl)->doc.arrangeBoard  = false;
  710.                 (*newFrHndl)->doc.locOfOpponent = senderTarget;
  711.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  712.                     &receiveGameList,    /* List to get from.            */
  713.                     3L,                    /* Get second item in list.        */
  714.                     typeFSS,            /* Third item is the FSSpec.    */
  715.                     &ignoredKeyWord,    /* Returned keyword -- we know. */
  716.                     &ignoredType,        /* Returned type -- we know.    */
  717.                     (Ptr)&myFSS,        /* Where to put the FSSpec.        */
  718.                     sizeof(FSSpec),        /* Size of the data.            */
  719.                     &ignoredSize        /* Actual size -- we know.        */
  720.                 );
  721.                 if (!err)
  722.                     pcpy((*newFrHndl)->fileState.fss.name, myFSS.name);
  723.             }
  724.             if (!err) {
  725.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  726.                     &receiveGameList,    /* List to get from.                */
  727.                     4L,                    /* Get second item in list.            */
  728.                     typePascal,            /* Third item is the opponent name.    */
  729.                     &ignoredKeyWord,    /* Returned keyword -- we know.     */
  730.                     &ignoredType,        /* Returned type -- we know.        */
  731.                     (Ptr)opponentName,    /* Where to put the opponent name.    */
  732.                     sizeof(Str32),        /* Size of the data.                */
  733.                     &ignoredSize        /* Actual size.                        */
  734.                 );
  735.                 (*newFrHndl)->doc.opponentName[0] = 0;
  736.                 if (!err) {
  737.                     pcpy((*newFrHndl)->doc.opponentName, opponentName);
  738.                     zone[0] = machine[0] = 0;
  739.                     GetTargetInfo(senderTarget, zone, machine, application);
  740.                     pcpy((*newFrHndl)->doc.opponentZone, zone);
  741.                     pcpy((*newFrHndl)->doc.opponentMachine, machine);
  742.                     GetDateTime(&((*newFrHndl)->doc.timeLastReceive));
  743.                 }
  744.                 if (!err) {
  745.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  746.                         &receiveGameList,    /* List to get from.                */
  747.                         5L,                    /* Get second item in list.            */
  748.                         typePascal2,        /* Third item is the opponent name.    */
  749.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  750.                         &ignoredType,        /* Returned type -- we know.        */
  751.                         (Ptr)reconnectPath,    /* Where to put the opponent name.    */
  752.                         sizeof(Str255),        /* Size of the data.                */
  753.                         &ignoredSize        /* Actual size.                        */
  754.                     );
  755.                     (*newFrHndl)->doc.reconnectPath[0] = 0;
  756.                     if (!err) pcpy((*newFrHndl)->doc.reconnectPath, reconnectPath);
  757.                 }
  758.                 if (!err) {
  759.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  760.                         &receiveGameList,    /* List to get from.                */
  761.                         6L,                    /* Get second item in list.            */
  762.                         typePascal3,        /* Third item is the opponent name.    */
  763.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  764.                         &ignoredType,        /* Returned type -- we know.        */
  765.                         (Ptr)reconnectApp,    /* Where to put the opponent name.    */
  766.                         sizeof(Str32),        /* Size of the data.                */
  767.                         &ignoredSize        /* Actual size.                        */
  768.                     );
  769.                     (*newFrHndl)->doc.reconnectApp[0] = 0;
  770.                     if (!err) pcpy((*newFrHndl)->doc.reconnectApp, reconnectApp);
  771.                 }
  772.             }
  773.         }
  774.     }
  775.  
  776.     if (!err) {        /* If we got the opponent address... */
  777.  
  778.         if (!twoPlayer) {        /* It is a new game... */
  779.  
  780.             (*newFrHndl)->doc.timerRefTick = TickCount();
  781.                 /* Set the timer reference early as possible.
  782.                 ** This syncs the two clocks as much as possible. */
  783.  
  784.                 /* For a new opponent, then we need to ID the receiver side
  785.                 ** of the sender/receiver ID pair.  We also need to send
  786.                 ** back the receiver portion of the ID pair for the sender. */
  787.  
  788.             (*newFrHndl)->doc.gameID_0 = gameID[0] = (TickCount() | 0x01);
  789.             (*newFrHndl)->doc.myColor     ^= 1;
  790.             (*newFrHndl)->doc.invertBoard ^= 1;
  791.                 /* We are the opposite color/side as the opponent. */
  792.  
  793.             if ((*newFrHndl)->doc.version != kVersion) err = errAEWrongDataType;
  794.                 /* Incompatible file format. */
  795.  
  796.             if (!err) {
  797.                 gameID[1] = (*newFrHndl)->doc.gameID_1;
  798.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  799.                     &reply,                /* The AppleEvent.              */
  800.                     keyGameID,            /* AEKeyword                 */
  801.                     typeDoubleLong,        /* Type code.                 */
  802.                     (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  803.                     2 * sizeof(long)    /* Size of data area.         */
  804.                 );
  805.             }
  806.  
  807.             if (!err) {
  808.                 opponentName[0] = 0;
  809.                 if (userNameHndl = GetResource('STR ', -16096))
  810.                     pcpy(opponentName, (StringPtr)(*userNameHndl));
  811.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  812.                     &reply,                /* The AppleEvent.              */
  813.                     keyPascalReply,        /* AEKeyword                 */
  814.                     typePascal,            /* Type code.                 */
  815.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  816.                     opponentName[0] + 1    /* Size of data area.         */
  817.                 );
  818.             }
  819.  
  820.             if (!err) {
  821.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  822.                 err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  823.                     &reply,                    /* The AppleEvent.              */
  824.                     keyPascal2Reply,        /* AEKeyword                 */
  825.                     typePascal2,            /* Type code.                 */
  826.                     (Ptr)reconnectPath,        /* Pointer to area for data. */ 
  827.                     reconnectPath[0] + 1    /* Size of data area.         */
  828.                 );
  829.                 if (!err) {
  830.                     err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  831.                         &reply,                    /* The AppleEvent.              */
  832.                         keyPascal3Reply,        /* AEKeyword                 */
  833.                         typePascal3,            /* Type code.                 */
  834.                         (Ptr)reconnectApp,        /* Pointer to area for data. */ 
  835.                         reconnectApp[0] + 1    /* Size of data area.         */
  836.                     );
  837.                 }
  838.             }
  839.  
  840.             if (!err) {
  841.                 if (IsAppWindow(fwindow = FrontWindow())) {
  842.                     frPtr = *(frHndl = (FileRecHndl)GetWRefCon(fwindow));
  843.                     if (
  844.                         (frPtr->doc.myColor != kMessageDoc) &&
  845.                         (!(frPtr->doc.arrangeBoard)) &&
  846.                         (!(frPtr->doc.twoPlayer)) &&
  847.                         (!(frPtr->doc.numGameMoves)) &&
  848.                         (!(frPtr->doc.gameID_0)) &&
  849.                         (!(frPtr->doc.timeLastReceive))
  850.                     ) {
  851.                         AppDisposeDocument(frHndl);
  852.                         DisposeAnyWindow(fwindow);
  853.                     }
  854.                 }
  855.                 behindWindow = (WindowPtr)-1;
  856. #ifdef __SYSEQU__
  857.                 for (wpeek = *(WindowPeek *)WindowList; wpeek; wpeek = wpeek->nextWindow) {
  858. #else
  859.                 for (wpeek = (WindowPeek)WindowList; wpeek; wpeek = wpeek->nextWindow) {
  860. #endif
  861.                     if (IsAppWindow((WindowPtr)wpeek)) {
  862.                         frPtr = *(FileRecHndl)GetWRefCon((WindowPtr)wpeek);
  863.                         if (
  864.                             (frPtr->doc.myColor != kMessageDoc) &&
  865.                             (!(frPtr->doc.arrangeBoard)) &&
  866.                             (!(frPtr->doc.twoPlayer)) &&
  867.                             (!(frPtr->doc.numGameMoves))
  868.                         ) break;
  869.                         behindWindow = (WindowPtr)wpeek;
  870.                     }
  871.                 }
  872.                 err = AppNewWindow(newFrHndl, nil, behindWindow);
  873.             }
  874.  
  875.                 /* If everything worked for new opponent, give the new document a window. */
  876.  
  877.             if (!err) {
  878.                 AdjustGameSlider(newFrHndl);
  879.  
  880.                 DrawButtonTitle(newFrHndl, kTwoPlayer);
  881.                     /* Convert the draw button to two player. */
  882.  
  883.                 (*newFrHndl)->doc.gotUpdateTick = TickCount();
  884.                     /* Record when we got the event. */
  885.  
  886.                 fwindow = FrontWindow();
  887.                 mssgFrHndl = (FileRecHndl)GetWRefCon((WindowPtr)fwindow);
  888.                 if ((*mssgFrHndl)->doc.myColor == kMessageDoc) {
  889.                     te     = (*mssgFrHndl)->doc.message[kMessageOut];
  890.                     hText  = (*te)->hText;
  891.                     hstate = LockHandleHigh(hText);
  892.                     size   = (*te)->teLength;
  893.                     err = AEPutParamPtr(
  894.                         &reply,
  895.                         keyTextMessage,
  896.                         typeMssg,
  897.                         *hText,
  898.                         size
  899.                     );
  900.                     HSetState(hText, hstate);
  901.                 }
  902.             }
  903.         }
  904.         else {        /* It is an update to an existing game. */
  905.  
  906.             window = GetGameWindow(
  907.                 (*newFrHndl)->doc.gameID_1, (*newFrHndl)->doc.gameID_0);
  908.                     /* Get the window for the existing game. */
  909.  
  910.             if (window) {        /* This game still exists... */
  911.  
  912.                 oldFrHndl = (FileRecHndl)GetWRefCon(window);
  913.                 UpdateTime(oldFrHndl, false);
  914.  
  915.                 if ((*oldFrHndl)->doc.resync < (sendReason = (*newFrHndl)->doc.sendReason))
  916.                     (*oldFrHndl)->doc.resync = sendReason;
  917.                         /* Bump up resync, if needed. */
  918.  
  919.                 if (sendReason == kScrolling) {
  920.                     if (
  921.                         ((*oldFrHndl)->doc.resync == kResync) || 
  922.                         ((*oldFrHndl)->doc.gotUpdateTick + 30 > TickCount())
  923.                     ) {
  924.                         window = nil;
  925.                         AppDisposeDocument(newFrHndl);
  926.                                 /* Temporary document now gone. */
  927.                     }    /* If it has been less than 1/2 second since the last
  928.                         ** scroll update received, or if the user has finished
  929.                         ** scrolling, then we can ignore this scroll event.
  930.                         ** This keeps us from getting behind in the processing
  931.                         ** of scroll events. */
  932.                 }
  933.             }
  934.             else
  935.                 err = memFullErr;
  936.                     /* Can't find the old window, so cause some kind of error. */
  937.  
  938.             if (window) {        /* This game still exists... */
  939.  
  940.                 if (sendReason != kIsMove) {
  941.                     for (i = 0; i < 2; ++i)
  942.                         (*newFrHndl)->doc.timeLeft[i] = (*oldFrHndl)->doc.timeLeft[i];
  943.                             /* Keep our clock values if opponent is scrolling or resyncing. */
  944.                 }
  945.  
  946.                 frPtr        = *oldFrHndl;
  947.                 oldGameIndex = frPtr->doc.gameIndex;
  948.                 oldNumMoves  = frPtr->doc.numGameMoves;
  949.                 oldGame      = frPtr->doc.gameMoves;
  950.                 frPtr        = *newFrHndl;
  951.                 newGameIndex = frPtr->doc.gameIndex;
  952.                 newNumMoves  = frPtr->doc.numGameMoves;
  953.                 newGame      = frPtr->doc.gameMoves;
  954.                 if ((oldGameIndex == newGameIndex) && (oldNumMoves == newNumMoves)) {
  955.                     optr = &(**oldGame)[0];
  956.                     nptr = &(**newGame)[0];
  957.                     identical = true;
  958.                     for (i = 0; i < oldNumMoves; ++i, ++optr, ++nptr) {
  959.                         if (
  960.                             (optr->moveFrom          != nptr->moveFrom) ||
  961.                             (optr->moveTo            != nptr->moveTo) ||
  962.                             (optr->pieceCaptured     != nptr->pieceCaptured) ||
  963.                             (optr->pieceCapturedFrom != nptr->pieceCapturedFrom) ||
  964.                             (optr->promoteTo         != nptr->promoteTo)
  965.                         ) {
  966.                             identical = false;
  967.                             break;
  968.                         }
  969.                     }
  970.                 }
  971.                 else identical = false;
  972.  
  973.                 myColor     = (*oldFrHndl)->doc.myColor;
  974.                 invertBoard = (*oldFrHndl)->doc.invertBoard;
  975.                     /* These need to be saved, so they are in that section,
  976.                     ** but they are private info, so cache them. */
  977.  
  978.                 ptr1 = (Ptr)&((*newFrHndl)->doc);
  979.                 ptr2 = (Ptr)&((*newFrHndl)->doc.endFileInfo1);
  980.                 size = (long)ptr2 - (long)ptr1;
  981.                 ptr2 = (Ptr)&((*oldFrHndl)->doc);
  982.                 BlockMove(ptr1, ptr2, size);
  983.  
  984.                 (*oldFrHndl)->doc.myColor     = myColor;
  985.                 (*oldFrHndl)->doc.invertBoard = invertBoard;
  986.                     /* Restore our private cached values. */
  987.  
  988.                 (*newFrHndl)->doc.gameMoves = (*oldFrHndl)->doc.gameMoves;
  989.                 (*oldFrHndl)->doc.gameMoves = gameMoves;
  990.                     /* Swap the game move handles.  The existing document
  991.                     ** is now updated completely.  We can dispose of the
  992.                     ** temporary new one.  (gameMoves is set above for
  993.                     ** the handle for the new document.) */
  994.  
  995.                 i = (*newFrHndl)->doc.drawBtnState;
  996.                 drawBtnState = kTwoPlayer;
  997.                 if (i & 0x02) drawBtnState |= 0x04;
  998.                 if (i & 0x04) drawBtnState |= 0x02;
  999.  
  1000.                 AppDisposeDocument(newFrHndl);
  1001.                     /* Temporary document now gone. */
  1002.  
  1003.                 GetPort(&oldPort);
  1004.                 SetPort(window);
  1005.  
  1006.                 if (!identical) {        /* There was a change, so show it. */
  1007.                     if (sendReason == kIsMove) {
  1008.                     if (GetCtlValue((*oldFrHndl)->doc.beepOnMove)) SysBeep(1);
  1009.                         if (GameStatus(oldFrHndl) <= kDrawByRep) {
  1010.                             MakeMove(oldFrHndl, -1, 0, 0);
  1011.                             oldGame      = (*oldFrHndl)->doc.gameMoves;
  1012.                             oldGameIndex = (*oldFrHndl)->doc.gameIndex;
  1013.                             fromSq = (**oldGame)[oldGameIndex].moveFrom;
  1014.                             toSq   = (**oldGame)[oldGameIndex].moveTo;
  1015.                             SlideThePiece(oldFrHndl, fromSq, toSq);
  1016.                             MakeMove(oldFrHndl, 1, 0, 0);
  1017.                         }
  1018.                     }
  1019.                     ImageDocument(oldFrHndl, true);
  1020.                     AdjustGameSlider(oldFrHndl);
  1021.                 }
  1022.  
  1023.                 DrawButtonTitle(oldFrHndl, drawBtnState);
  1024.                 UpdateGameStatus(oldFrHndl);
  1025.                     /* Update the text of the draw button. */
  1026.  
  1027.                 DrawTime(oldFrHndl);
  1028.  
  1029.                 (*oldFrHndl)->doc.gotUpdateTick = TickCount();
  1030.                     /* Record when we got the event. */
  1031.  
  1032.                 if (sendReason == kIsMove) {
  1033.                     (*oldFrHndl)->fileState.docDirty = true;
  1034.                     AlertIfGameOver(oldFrHndl);
  1035.                         /* For non-moves, we don't want to beep or
  1036.                         ** show a game-over dialog. */
  1037.                 }
  1038.                 SetPort(oldPort);
  1039.             }
  1040.         }
  1041.     }
  1042.  
  1043.     if (err) AppDisposeDocument(newFrHndl);
  1044.         /* This won't get done twice, even though there is an
  1045.         ** AppDisposeDocument(newFrHndl) earlier.  The earlier
  1046.         ** one only happens if no error occured, and this one
  1047.         ** only happens on an error condition. */
  1048.  
  1049.     AEDisposeDesc(&receiveGameList);
  1050.         /* Dispose of the descriptors, created or not.
  1051.         ** If not created, no harm done by calling. */
  1052.  
  1053.     if (!err) NotifyUser();
  1054.     return(err);
  1055. }
  1056.  
  1057.  
  1058.  
  1059. /*****************************************************************************/
  1060.  
  1061.  
  1062.  
  1063. /* SendMssg
  1064. **
  1065. ** Send one of various messages to the opponent.  There is a common set of
  1066. ** data that needs to be sent so that the opponent can determine which game
  1067. ** the message should be applied.  Then there is message-specific data that
  1068. ** is handled case by case.  Once the message is completed, it is sent off
  1069. ** to the opponent.  The additional task of updating the state of our game
  1070. ** is also handled here.  For example:  When text is sent, the text on our
  1071. ** machine is selected to make it easier to replace the old text with new
  1072. ** text.  Any typing by the user will replace the selected text (all the text)
  1073. ** with the newly typed text.  */
  1074.  
  1075. #pragma segment AppleEvents
  1076. Boolean    SendMssg(FileRecHndl frHndl, short messageType)
  1077. {
  1078.     AEAddressDesc    locOfOpponent;
  1079.     OSErr            err;
  1080.     TEHandle        te;
  1081.     char            hstate;
  1082.     AppleEvent        theAevt, reply;
  1083.     Handle            hText, snd;
  1084.     long            size, gameID[2], time[2];
  1085.     short            i;
  1086.     Boolean            twoPlayer;
  1087.     WindowPtr        oldPort;
  1088.  
  1089.     oldPort = SetFilePort(frHndl);
  1090.  
  1091.     theAevt.dataHandle = reply.dataHandle = nil;
  1092.         /* Make sure disposing of the descriptors is okay in all cases.
  1093.         ** This will not be necessary after 7.0b3, since the calls that
  1094.         ** attempt to create the descriptors will nil automatically
  1095.         ** upon failure. */
  1096.  
  1097.     err = noErr;
  1098.  
  1099.     if (twoPlayer = (*frHndl)->doc.twoPlayer) {
  1100.  
  1101.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1102.  
  1103.         err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  1104.             kCustomEventClass,            /* Event class.                 */
  1105.             kibitzAESendMssg,            /* Event ID.                 */
  1106.             &locOfOpponent,                /* Address of receiving app. */
  1107.             kAutoGenerateReturnID,        /* This value causes the     */
  1108.                                         /* AppleEvent manager to     */
  1109.                                         /* assign a return ID that     */
  1110.                                         /* is unique to the session. */
  1111.             kAnyTransactionID,            /* Ignore transaction ID.     */
  1112.             &theAevt                    /* Location of event.         */
  1113.         );
  1114.  
  1115.         if (!err) {            /* Say what the message is. */
  1116.             AEPutParamPtr(
  1117.                 &theAevt,
  1118.                 keyDirectObject,
  1119.                 typeShortInteger,
  1120.                 (Ptr)&messageType,
  1121.                 sizeof(short)
  1122.             );
  1123.         }
  1124.  
  1125.         if (!err) {            /* Say what window message is for. */
  1126.             gameID[0] = (*frHndl)->doc.gameID_0;
  1127.             gameID[1] = (*frHndl)->doc.gameID_1;
  1128.             AEPutParamPtr(
  1129.                 &theAevt,
  1130.                 keyGameID,
  1131.                 typeDoubleLong,
  1132.                 (Ptr)&gameID[0],
  1133.                 2 * sizeof(long)
  1134.             );
  1135.         }
  1136.     }
  1137.  
  1138.     /* The stuff that applies to all messages is now done.  Now specifically
  1139.     ** handle all the different message types. */
  1140.  
  1141.     if (!err) {
  1142.         switch (messageType) {
  1143.  
  1144.             case kAmWhiteMssg:
  1145.             case kAmBlackMssg:
  1146.                 (*frHndl)->doc.configColor       = messageType;
  1147.                 (*frHndl)->doc.configColorChange = true;
  1148.                 (*frHndl)->doc.resync            = kHandResync;
  1149.                     /* The AppleEvent already has all the data the opponent
  1150.                     ** needs.  Post that a color change is happening.  The
  1151.                     ** reason that it is posted, instead of immediately applied,
  1152.                     ** is that we want to make sure that the opponent isn't
  1153.                     ** doing a color change operation at the same time.  The
  1154.                     ** color change will only occur when we get a NULL event.
  1155.                     ** The NULL event indicates that the opponent isn't sending
  1156.                     ** any AppleEvents at that time.  Waiting for quiescence
  1157.                     ** helps prevent the state of the game from getting
  1158.                     ** confused.  Also, the creator of the game echos the
  1159.                     ** color change, just to make sure that both machines are
  1160.                     ** in the same state.  (The echo doesn't occur until
  1161.                     ** there are no other AppleEvents happening.  This helps
  1162.                     ** keep the number of AppleEvents down, as well.) */
  1163.                 break;
  1164.  
  1165.             case kDisconnectMssg:
  1166.                     /* All the information we need is already in the AppleEvent. */
  1167.                 break;
  1168.  
  1169.             case kTimeMssg:
  1170.                 for (i = 0; i < 2; ++i)
  1171.                     time[i] = (*frHndl)->doc.configTime[i] = (*frHndl)->doc.timeLeft[i];
  1172.                 if (twoPlayer) {
  1173.                     err = AEPutParamPtr(
  1174.                         &theAevt,
  1175.                         keyTime,
  1176.                         typeDoubleLong,
  1177.                         (Ptr)&time[0],
  1178.                         2 * sizeof(long)
  1179.                     );
  1180.                     if ((*frHndl)->doc.resync)
  1181.                         (*frHndl)->doc.configTimeChange = true;
  1182.                     else {
  1183.                         for (i = 0; i < 2; ++i)
  1184.                             (*frHndl)->doc.timeLeft[i] =
  1185.                                 (*frHndl)->doc.displayTime[i] =
  1186.                                     (*frHndl)->doc.configTime[i];
  1187.                         UpdateTime(frHndl, false);
  1188.                         DrawTime(frHndl);
  1189.                     }
  1190.                 }
  1191.                 break;
  1192.  
  1193.             case kTextMssg:
  1194.                 if (twoPlayer) {
  1195.                     te     = (*frHndl)->doc.message[kMessageOut];
  1196.                     hText  = (*te)->hText;
  1197.                     hstate = LockHandleHigh(hText);
  1198.                     size   = (*te)->teLength;
  1199.                     err = AEPutParamPtr(
  1200.                         &theAevt,
  1201.                         keyTextMessage,
  1202.                         typeMssg,
  1203.                         *hText,
  1204.                         size
  1205.                     );
  1206.                     HSetState(hText, hstate);
  1207.                 }
  1208.                 break;
  1209.  
  1210.             case kSoundMssg:
  1211.                 if (twoPlayer) {
  1212.                     if (snd = (*frHndl)->doc.sound) {
  1213.                         hstate = LockHandleHigh(snd);
  1214.                         size   = GetHandleSize(snd);
  1215.                         err = AEPutParamPtr(
  1216.                             &theAevt,
  1217.                             keySoundMessage,
  1218.                             typeMssg,
  1219.                             *snd,
  1220.                             size
  1221.                         );
  1222.                         HSetState(snd, hstate);
  1223.                     }
  1224.                 }
  1225.                 break;
  1226.         }
  1227.     }
  1228.  
  1229.     if (twoPlayer) {
  1230.         if (!err) {        /* If everything looks good... */
  1231.             err = AESend(                /* SEND APPLEEVENT.                 */
  1232.                 &theAevt,                /* Our Apple Event to send.         */
  1233.                 &reply,                    /* We may have a reply.             */
  1234.                 kAENoReply,                /* Don't wait for reply.         */
  1235.                 PRIORITY,                /* App. send priority.             */
  1236.                 0,                        /* We aren't waiting.             */
  1237.                 nil,                    /* We don't wait, so no idleProc */
  1238.                 nil                        /* EventFilterProcPtr.             */
  1239.             );
  1240.         }
  1241.         if (!err) {
  1242.             switch (messageType) {
  1243.                 case kTextMssg:
  1244.                     CTESetSelect(0, (*te)->teLength, te);
  1245.                         /* Select all the text so entering the next message
  1246.                         ** is more convenient. */
  1247.                     break;
  1248.                 case kSoundMssg:
  1249.                     SndPlay(nil, (*frHndl)->doc.sound, false);
  1250.                     break;
  1251.             }
  1252.         }
  1253.  
  1254.         AEDisposeDesc(&theAevt);
  1255.         AEDisposeDesc(&reply);
  1256.             /* Dispose of the descriptors, created or not.
  1257.             ** If not created, no harm done by calling. */
  1258.     }
  1259.  
  1260.     SetPort(oldPort);
  1261.     return(err);
  1262. }
  1263.  
  1264.  
  1265.  
  1266. /*****************************************************************************/
  1267.  
  1268.  
  1269.  
  1270. #pragma segment AppleEvents
  1271. pascal OSErr    ReceiveMssg(AppleEvent message, AppleEvent reply, long refcon)
  1272. {
  1273. #pragma unused (refcon)
  1274.  
  1275.     OSErr            err;
  1276.     long            gameID[2], time[2];
  1277.     short            messageType, i;
  1278.     WindowPtr        window;
  1279.     FileRecHndl        frHndl;
  1280.     DescType        actualType;
  1281.     long            actualSize, mssgSize;
  1282.     unsigned long    key;
  1283.     char            hstate;
  1284.     Handle            mssgData;
  1285.     AEAddressDesc    locOfOpponent;
  1286.  
  1287.     err = noErr;
  1288.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  1289.         &reply,                    /* The AppleEvent.              */
  1290.         keyReplyErr,            /* AEKeyword                 */
  1291.         typeShortInteger,        /* Desired type.             */
  1292.         (Ptr)&err,                /* Pointer to area for data. */ 
  1293.         sizeof(short)            /* Size of data area.         */
  1294.     );
  1295.  
  1296.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  1297.         &message,                /* The AppleEvent.              */
  1298.         keyDirectObject,        /* AEKeyword                 */
  1299.         typeShortInteger,        /* Desired type.             */
  1300.         &actualType,            /* Type code.                 */
  1301.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  1302.         2 * sizeof(long),        /* Size of data area.         */
  1303.         &actualSize                /* Returned size of data.     */
  1304.     );
  1305.  
  1306.     if (!err) {
  1307.         err = AEGetParamPtr(        /* GET WINDOW MESSAGE IS FOR. */
  1308.             &message,                /* The AppleEvent.               */
  1309.             keyGameID,                /* AEKeyword                  */
  1310.             typeDoubleLong,            /* Desired type.              */
  1311.             &actualType,            /* Type code.                  */
  1312.             (Ptr)&gameID[0],        /* Pointer to area for data.  */ 
  1313.             2 * sizeof(long),        /* Size of data area.          */
  1314.             &actualSize                /* Returned size of data.      */
  1315.         );
  1316.     }
  1317.  
  1318.     if (!err) {            /* See if the requested window exists... */
  1319.         if (window = GetGameWindow(gameID[1], gameID[0])) {
  1320.             frHndl = (FileRecHndl)GetWRefCon(window);
  1321.                 /* The game still exists... */
  1322.         }
  1323.         else
  1324.             err = userCanceledErr;
  1325.                 /* User (or computer) canceled game by disconnecting improperly. */
  1326.     }
  1327.  
  1328.     if (!err) {        /* If everything is cool, then do the specific task... */
  1329.  
  1330.         switch(messageType) {
  1331.  
  1332.             case kAmWhiteMssg:
  1333.             case kAmBlackMssg:
  1334.                 messageType ^= 1;
  1335.                 (*frHndl)->doc.configColor       = messageType;
  1336.                 (*frHndl)->doc.configColorChange = true;
  1337.                 (*frHndl)->doc.resync            = kHandResync;
  1338.                 if ((*frHndl)->doc.creator)
  1339.                     SendMssg(frHndl, messageType);
  1340.                         /* If we are the creator, echo the message to make sure
  1341.                         ** that both players aren't the same color. */
  1342.                 break;
  1343.  
  1344.             case kDisconnectMssg:
  1345.                 locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1346.                 AEDisposeDesc(&locOfOpponent);
  1347.                 (*frHndl)->doc.twoPlayer = kLimbo;
  1348.                     /* We set the state of the game to NOT two-player, and NOT
  1349.                     ** what we are now.  This allows us to call SetOpponentType
  1350.                     ** to do all the work we need done.  If we didn't fudge the
  1351.                     ** state of the game (from two-player) then SetOpponentType
  1352.                     ** would send a disconnect message (and we would end up
  1353.                     ** back here.)  This would be an ugly situation, which is
  1354.                     ** completely prevented by fudging the state of the game. */
  1355.                 SetOpponentType(frHndl, kOnePlayer);
  1356.                 break;
  1357.  
  1358.             case kTimeMssg:
  1359.                 AEGetParamPtr(
  1360.                     &message,                /* The AppleEvent.              */
  1361.                     keyTime,                /* AEKeyword                 */
  1362.                     typeDoubleLong,            /* Desired type.             */
  1363.                     &actualType,            /* Type code.                 */
  1364.                     (Ptr)&time[0],            /* Pointer to area for data. */ 
  1365.                     2 * sizeof(long),        /* Size of data area.         */
  1366.                     &mssgSize                /* Returned size of data.     */
  1367.                 );
  1368.                 for (i = 0; i < 2; ++i)
  1369.                     (*frHndl)->doc.configTime[i] = time[i];
  1370.                 if ((*frHndl)->doc.resync)
  1371.                     (*frHndl)->doc.configTimeChange = true;
  1372.                 else {
  1373.                     for (i = 0; i < 2; ++i)
  1374.                         (*frHndl)->doc.timeLeft[i] =
  1375.                             (*frHndl)->doc.displayTime[i] = time[i];
  1376.                     UpdateTime(frHndl, false);
  1377.                     DrawTime(frHndl);
  1378.                 }
  1379.                 if ((*frHndl)->doc.creator)
  1380.                     SendMssg(frHndl, kTimeMssg);
  1381.                         /* If we are the creator, echo the message to make sure
  1382.                         ** the clocks are in sync. */
  1383.                 break;
  1384.  
  1385.             case kTextMssg:
  1386.             case kSoundMssg:
  1387.                 /* Both the text and sound message simply send a block of
  1388.                 ** data less than 32k.  Get the data from the AppleEvent
  1389.                 ** for both cases, and then decide what kind of data it is. */
  1390.  
  1391.                 key = (messageType == kTextMssg) ? keyTextMessage : keySoundMessage;
  1392.                 if (!err) {        /* Determine the size of the data... */
  1393.                     err = AEGetParamPtr(
  1394.                         &message,                /* The AppleEvent.              */
  1395.                         key,                    /* AEKeyword                 */
  1396.                         typeMssg,                /* Desired type.             */
  1397.                         &actualType,            /* Type code.                 */
  1398.                         nil,                    /* Pointer to area for data. */ 
  1399.                         0,                        /* Size of data area.         */
  1400.                         &mssgSize                /* Returned size of data.     */
  1401.                     );
  1402.                 }
  1403.                 mssgData = nil;
  1404.                 if (!err) {        /* Get the data... */
  1405.                     mssgData = NewHandle(mssgSize);
  1406.                     if (mssgData) {
  1407.                         hstate = LockHandleHigh(mssgData);
  1408.                         err = AEGetParamPtr(
  1409.                             &message,                /* The AppleEvent.              */
  1410.                             key,                    /* AEKeyword                 */
  1411.                             typeMssg,                /* Desired type.             */
  1412.                             &actualType,            /* Type code.                 */
  1413.                             *mssgData,                /* Pointer to area for data. */ 
  1414.                             mssgSize,                /* Size of data area.         */
  1415.                             &actualSize                /* Returned size of data.     */
  1416.                         );
  1417.                     }
  1418.                     else err = memFullErr;
  1419.                 }
  1420.                 if (!err) {
  1421.                     if (messageType == kTextMssg) {
  1422.                         mssgData = CTESwapText((*frHndl)->doc.message[kMessageIn], mssgData, true);
  1423.                         if (GetCtlValue((*frHndl)->doc.beepOnMssg))
  1424.                             if (mssgSize) SysBeep(1);
  1425.                     }
  1426.                     else SndPlay(nil, mssgData, false);
  1427.                 }
  1428.                 if (mssgData) DisposHandle(mssgData);
  1429.                 if (!err) NotifyUser();
  1430.                 break;
  1431.  
  1432.             case kBeepMssg:
  1433.                 SysBeep(1);
  1434.                 break;
  1435.  
  1436.         }
  1437.     }
  1438.  
  1439.     return(err);
  1440. }
  1441.  
  1442.  
  1443.  
  1444. /*****************************************************************************/
  1445. /*****************************************************************************/
  1446.  
  1447.  
  1448.  
  1449. /* GetGameWindow
  1450. **
  1451. ** Find the window with the specified game ID's. */
  1452.  
  1453. #pragma segment AppleEvents
  1454. WindowPtr    GetGameWindow(long gameID_0, long gameID_1)
  1455. {
  1456.     WindowPeek    window;
  1457.     FileRecHndl    frHndl;
  1458.  
  1459. #ifdef __SYSEQU__
  1460.     for (window = *(WindowPeek *)WindowList; window; window = window->nextWindow) {
  1461. #else
  1462.     for (window = (WindowPeek)WindowList; window; window = window->nextWindow) {
  1463. #endif
  1464.         if (IsAppWindow((WindowPtr)window)) {
  1465.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  1466.             if (
  1467.                 ((*frHndl)->doc.gameID_0 == gameID_0) &&
  1468.                 ((*frHndl)->doc.gameID_1 == gameID_1)
  1469.             ) return((WindowPtr)window);
  1470.         }
  1471.     }
  1472.  
  1473.     return(nil);
  1474. }
  1475.  
  1476.  
  1477.  
  1478. /*****************************************************************************/
  1479.  
  1480.  
  1481.  
  1482. /* KibitzPortFilter
  1483. **
  1484. ** Don't allow PPCBrowser to show any applications other than Kibitz. */
  1485.  
  1486. #pragma segment AppleEvents
  1487. pascal Boolean    KibitzPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1488. {
  1489. #pragma unused (locationName)
  1490.  
  1491.     long    type;
  1492.  
  1493.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1494.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1495.             /* The BlockMove is so that we don't get an address error
  1496.             ** on a 68000-based machine due to referencing a long at
  1497.             ** an odd-address. */
  1498.         if (type == gameCreator) return(true);
  1499.     }
  1500.  
  1501.     return(false);
  1502. }
  1503.  
  1504.  
  1505.  
  1506. /*****************************************************************************/
  1507.  
  1508.  
  1509.  
  1510. /* SetOpponentType
  1511. **
  1512. ** Change the opponent type from whatever it currently is to the specified
  1513. ** type.  In so doing, change the state of any controls, etc., that need
  1514. ** to be changed due to the new opponent type. */
  1515.  
  1516. #pragma segment AppleEvents
  1517. void    SetOpponentType(FileRecHndl frHndl, short newOpponentType)
  1518. {
  1519.     WindowPtr        oldPort, window;
  1520.     short            oldOpponentType, hilite, i, toggle;
  1521.     AEAddressDesc    locOfOpponent;
  1522.     Rect            boardRect;
  1523.     ControlHandle    ctl;
  1524.     RgnHandle        oldClip, newClip;
  1525.  
  1526.     if (!(*frHndl)->fileState.window) return;
  1527.  
  1528.     if (!(oldOpponentType = (*frHndl)->doc.arrangeBoard))
  1529.         oldOpponentType = (*frHndl)->doc.twoPlayer;
  1530.  
  1531.     if (oldOpponentType == newOpponentType) return;
  1532.  
  1533.     (*frHndl)->doc.arrangeBoard = false;
  1534.  
  1535.     oldPort = SetFilePort(frHndl);
  1536.     GetPort(&window);
  1537.  
  1538.     oldClip = NewRgn();
  1539.     newClip = NewRgn();
  1540.     GetClip(oldClip);
  1541.  
  1542.     toggle = false;
  1543.     if ((newOpponentType == kArrangeBoard) || (oldOpponentType == kArrangeBoard)) {
  1544.         toggle = true;
  1545.         SetClip(newClip);        /* Prevent stuff from drawing. */
  1546.     }
  1547.  
  1548.     if (oldOpponentType == kTwoPlayer) {
  1549.         SendMssg(frHndl, kDisconnectMssg);
  1550.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1551.         AEDisposeDesc(&locOfOpponent);
  1552.     }
  1553.  
  1554.     if (newOpponentType == kTwoPlayer) {
  1555.         hilite = 0;
  1556.         (*frHndl)->doc.timerRefTick = TickCount();
  1557.         (*frHndl)->doc.creator = true;
  1558.         if ((*frHndl)->doc.myColor == WHITE) (*frHndl)->doc.compMovesBlack = false;
  1559.         else                                 (*frHndl)->doc.compMovesWhite = false;
  1560.     }
  1561.     else {
  1562.         hilite = 255;
  1563.         (*frHndl)->doc.creator = false;
  1564.         (*frHndl)->doc.resync  = kIsMove;
  1565.         (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  1566.     }
  1567.  
  1568.     SetPort(window);
  1569.  
  1570.     if (newOpponentType == kArrangeBoard) {
  1571.         CTEActivate(false, CTEFindActive(window));
  1572.         (*frHndl)->doc.king[BLACK].rookMoves[QSIDE] = 0;
  1573.         (*frHndl)->doc.king[BLACK].rookMoves[KSIDE] = 0;
  1574.         (*frHndl)->doc.king[WHITE].rookMoves[QSIDE] = 0;
  1575.         (*frHndl)->doc.king[WHITE].rookMoves[KSIDE] = 0;
  1576.         (*frHndl)->doc.enPasMove        = 0;
  1577.         (*frHndl)->doc.enPasPawnLoc     = 0;
  1578.         (*frHndl)->doc.arngEnPasMove    = 0;
  1579.         (*frHndl)->doc.arngEnPasPawnLoc = 0;
  1580.         (*frHndl)->doc.numLegalMoves    = 0;
  1581.         (*frHndl)->doc.gameIndex        = 0;
  1582.         (*frHndl)->doc.numGameMoves     = 0;
  1583.         (*frHndl)->doc.compMovesWhite   = false;
  1584.         (*frHndl)->doc.compMovesBlack   = false;
  1585.         AdjustGameSlider(frHndl);
  1586.     }
  1587.     if (oldOpponentType == kArrangeBoard) CTEWindActivate(window);
  1588.  
  1589.     if (newOpponentType == kArrangeBoard) {
  1590.         (*frHndl)->doc.arrangeBoard = kArrangeBoard;
  1591.         newOpponentType = kOnePlayer;
  1592.     }
  1593.     (*frHndl)->doc.twoPlayer = newOpponentType;
  1594.  
  1595.     HiliteControl(ctl = (*frHndl)->doc.sendMessage, hilite);
  1596.     OutlineControl(ctl);
  1597.     HiliteControl((*frHndl)->doc.beepOnMove, hilite);
  1598.     HiliteControl((*frHndl)->doc.beepOnMssg, hilite);
  1599.  
  1600.     if (!SoundInputAvaliable()) hilite = 255;
  1601.     HiliteControl((*frHndl)->doc.record, hilite);
  1602.     if (!(*frHndl)->doc.sound) hilite = 255;
  1603.     HiliteControl((*frHndl)->doc.sendSnd, hilite);
  1604.     DrawButtonTitle(frHndl, newOpponentType);
  1605.  
  1606.     if (toggle) {
  1607.         SetClip(oldClip);
  1608.         for (i = 0; i < 2; ++i) (*frHndl)->doc.timeLeft[i] = -1;
  1609.         boardRect = BoardRect();
  1610.         boardRect.left = boardRect.right + 1;
  1611.         boardRect.right = 1000;
  1612.         EraseRect(&boardRect);
  1613.         ImageDocument(frHndl, false);
  1614.     }
  1615.  
  1616.     DisposeRgn(oldClip);
  1617.     DisposeRgn(newClip);
  1618.     SetPort(oldPort);
  1619. }
  1620.  
  1621.  
  1622.  
  1623. /*****************************************************************************/
  1624.  
  1625.  
  1626.  
  1627. #pragma segment AppleEvents
  1628. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  1629. {
  1630.     ProcessSerialNumber    psn;
  1631.     ProcessInfoRec        pinfo;
  1632.     FSSpec                fss;
  1633.  
  1634.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1635.     pinfo.processName       = app;
  1636.     pinfo.processAppSpec    = &fss;
  1637.  
  1638.     psn.lowLongOfPSN  = kCurrentProcess;
  1639.     psn.highLongOfPSN = kNoProcess;
  1640.     GetProcessInformation(&psn, &pinfo);
  1641.  
  1642.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  1643. }
  1644.  
  1645.  
  1646.  
  1647. /*****************************************************************************/
  1648.  
  1649.  
  1650.  
  1651. /* Don't allow DoIPCListPorts to find anything but the finder. */
  1652.  
  1653. #pragma segment AppleEvents
  1654. static pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1655. {
  1656. #pragma unused (locationName)
  1657.  
  1658.     OSType    type;
  1659.  
  1660.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1661.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1662.             /* The BlockMove is so that we don't get an address error
  1663.             ** on a 68000-based machine due to referencing a long at
  1664.             ** an odd-address. */
  1665.         if (type == 'MACS') return(true);
  1666.     }
  1667.  
  1668.     return(false);
  1669. }
  1670.  
  1671. OSErr    GetRemoteFinderTarget(FileRecHndl frHndl, AEDesc *retDesc)
  1672. {
  1673.     OSErr            err;
  1674.     char            hstate;
  1675.     PortInfoRec        info;        /* Just one, please. */
  1676.     LocationNameRec    loc;
  1677.     short            indx, reqCount, actCount;
  1678.     TargetID        theID;
  1679.  
  1680.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  1681.  
  1682.     hstate = LockHandleHigh((Handle)frHndl);
  1683.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  1684.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->doc.reconnectMachine);
  1685.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->doc.reconnectZone);
  1686.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  1687.     HSetState((Handle)frHndl, hstate);
  1688.  
  1689.     indx     = 0;
  1690.     reqCount = 1;
  1691.     actCount = 0;
  1692.     if (err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, FinderFilter)) return(err);
  1693.  
  1694.     theID.name = info.name;
  1695.     theID.location = loc;
  1696.     err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  1697.  
  1698.     return(err);
  1699. }
  1700.  
  1701.  
  1702.  
  1703.